<?php

function scanAllFiles(string $directory): array
{
    $filePaths = [];

    if (!is_dir($directory)) {
        return $filePaths; // return empty if not a valid directory
    }

    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS)
    );

    foreach ($iterator as $fileInfo) {
        if ($fileInfo->isFile()) {
            $filePaths[] = $fileInfo->getPathname();
        }
    }

    return $filePaths;
}

function extractVueComponentPath(string $path): String|null
{
    $normalizedPath = str_replace('\\', '/', $path);

    $pos = strpos($normalizedPath, 'src');

    if ($pos !== false) {
        $result = substr($normalizedPath, $pos);
        return $result;  // Output: src/components/Editor.vue
    } else {
        return null;
    }
}

function codeContainsComponents(string $filePath): bool
{
    if (!is_file($filePath) || !is_readable($filePath)) {
        return false;
    }

    $content = file_get_contents($filePath);

    return str_contains($content, '@/components') && str_contains($content, 'import') && str_contains($content, 'from');
}


function extractComponentImports(string $code): array
{
    $code = str_replace("\r\n", "\n", $code);
    preg_match_all('/^\s*import\s+.*?[\'"]@\/components\/.*?[\'"]\s*;?/m', $code, $matches);
    return $matches[0];
}

/**
 * @param $filePath
 * @return array
 * 通过文件路径，获得代码，查看是否存在import, from, @/components/这几个字符串，如果存在的话，就先组成这个组件的基本信息
 * 如slug, title, children:[], 这三个，然后通过import语句，获得组件的slug，title，children:[], 放到组件的数组里面的children里面
 */

function buildVueComponentTree($filePath)
{
    $code_content = file_get_contents($filePath);

    $component_info = getComponentInfo($filePath);
    $component_title = $component_info['title'];
    $component_slug = $component_info['slug'];
    $root = [
        'slug' => $component_slug,
        'title' => $component_title,
        'children' => [],
    ];

    if(str_contains($code_content, '@/components')){

        //from components import statement get file path
        $child_imports = extractComponentImports($code_content);

        foreach($child_imports as $import_statement){
            $child_file_path = storage_path('projects/vue1/src/'.str_replace('@/components', '', $import_statement));
            $root['children'][] = [
                'slug' => $component_slug,
                'title' => $component_title,
                'children' => [],
            ];
            buildVueComponentTree($child_file_path);
        }
    }

    return $root;

}

function executeCommand($cmd, $cwd)
{
    $descriptorspec = [
        0 => ["pipe", "r"],  // stdin
        1 => ["pipe", "w"],  // stdout
        2 => ["pipe", "w"],  // stderr
    ];

    $pipes = [];

    $env = [
        'PATH' => '/www/server/nodejs/v22.17.0/bin/npm', // Adjust to include your `npm` path
        'NODE_ENV' => 'production'
    ];

    $process = proc_open($cmd, $descriptorspec, $pipes, $cwd);

    if (is_resource($process)) {

        fclose($pipes[0]);

        $output = stream_get_contents($pipes[1]);
        fclose($pipes[1]);

        $errors = stream_get_contents($pipes[2]);
        fclose($pipes[2]);

        $return_value = proc_close($process);

        return ['output' => $output, 'error' => $errors, 'code' => $return_value];
    }

    return null;
}

function copyContentsFromOneDirectoryToAnother($sourceDir, $destinationDir)
{
    if (!is_dir($sourceDir)) {
        throw new Exception("Source directory does not exist.");
    }

    if (!is_dir($destinationDir)) {
        mkdir($destinationDir);
    }

    $files = scandir($sourceDir);
    foreach ($files as $file) {
        if ($file != '.' && $file != '..') {
            $sourceFile = $sourceDir . '/' . $file;
            $destinationFile = $destinationDir . '/' . $file;
            if (is_file($sourceFile)) {
                copy($sourceFile, $destinationFile);
            } elseif (is_dir($sourceFile)) {
                mkdir($destinationFile);
                copyContentsFromOneDirectoryToAnother($sourceFile, $destinationFile);
            }
        }
    }
}

function getComponentInfo($file_path):Array
{
    $project_path = extractProjectPath($file_path);
    $file_name = basename($file_path);
    $file_name = str_replace(".vue", "", $file_name);
    $file_name = strtolower(preg_replace("/[A-Z]/", '-$0', lcfirst($file_name)));
    $title = str_replace("-", " ", $file_name);
    $file_content = file_get_contents($file_path);
    $npm_dependencies = extractNpmDependencies($file_content);
    $packageJsonContent = file_get_contents($project_path."/package.json");
    $npm_dependencies = addVersionsToDependencies($npm_dependencies, $packageJsonContent);

    $local_components = extractLocalChildComponents($file_content);

    $relative_path = extractVueComponentPath($file_path);
    $import_statement = str_replace("src","@", $relative_path);

    return [
        'slug' => $file_name,
        'title' => ucwords($title),
        'relative_path' => $relative_path,
        'child_components' => $local_components,
        'npm_dependencies' => $npm_dependencies,
        'import_statement' => $import_statement,
//        'component_tree_json' => buildVueComponentTree($file_path),
        'code' =>  $file_content,
        'count' => count($local_components),
    ];
}

function extractNpmDependencies($code):Array
{
    $dependencies = [];
    preg_match_all('/import\s+(?:.*?\s+from\s+)?[\'"]([^\'"]+)[\'"]/', $code, $matches);
    foreach ($matches[1] as $module) {
        if (!preg_match('/^(\.\/|\.\.\/|\/)/', $module)) {
            $dependencies[] = $module;
        }
    }
    return array_unique($dependencies); // Remove duplicates
}

function addVersionsToDependencies(array $names, string $packageJsonContent): Array
{
    $package = json_decode($packageJsonContent, true);

    if (!isset($package['dependencies'])) {
        return []; // No dependencies found
    }

    $dependencies = $package['dependencies'];
    $result = [];

    foreach ($names as $name) {
        if (isset($dependencies[$name])) {
            $result[] = [
                'name' => $name,
                'version' => $dependencies[$name]
            ];
        }
    }

    return $result;
}

function extractLocalChildComponents(string $code): array
{
    $components = [];

    preg_match_all('/import\s+.*?\s+from\s+[\'"]([^\'"]+)["\']/', $code, $matches);

    foreach ($matches[1] as $path) {
        if (strpos($path, '@/components') !== false) {
            $parts = explode('/', $path);
            $filename = end($parts);
            $components[] = $filename;
        }
    }

    return array_unique($components);
}

function extractProjectPath($file_path){
    $normalizedPath = str_replace('\\', '/', $file_path);
    $pos = strpos($normalizedPath, 'src');

    if ($pos !== false) {
        $beforeSrc = substr($normalizedPath, 0, $pos);
        return $beforeSrc;
    } else {
        return null;
    }
}

function getPreviewHtml($component_path):string
{
    $component_info = getComponentInfo($component_path);
    $project_path = extractProjectPath($component_path);
    $component_file_name = basename($component_path);
    $component_file_name = str_replace(".vue", "", $component_file_name);
    $app_path = $project_path.'src/App.vue';
    $vite_config_path = $project_path.'vite.config.js';
    $app_content = file_get_contents($app_path);
    $vite_config_content = file_get_contents($vite_config_path);
    $app_content = str_replace('@/components/HelloWorld.vue', $component_info['import_statement'], $app_content);
    $app_content = str_replace('import HelloWorld', 'import '.$component_file_name, $app_content);
    $app_content = str_replace('<HelloWorld />', '<'.$component_file_name.' />', $app_content);
    $vite_config_content = str_replace('test1', $component_info['slug'], $vite_config_content);
    file_put_contents($app_path, $app_content);
    file_put_contents($vite_config_path, $vite_config_content);

    $output = executeCommand('npm run build', $project_path);

    if($output["output"]){

        $compiled_folder = $project_path.'dist/'.$component_info['slug'];

        if(!is_dir($compiled_folder)){
            mkdir($compiled_folder);
        }

        $preview_html = file_get_contents($compiled_folder.'/index.html');

        $preview_html = str_replace('/'.$component_info["slug"].'.js', $component_info["slug"].'.js', $preview_html);
        $preview_html = str_replace('/'.$component_info["slug"].'.css', $component_info["slug"].'.css', $preview_html);

        $public_demo_folder = public_path('/demo');

        if(!is_dir($public_demo_folder)){
            mkdir($public_demo_folder);
        }

        $public_component_folder = $public_demo_folder .'/'. $component_info['slug'];

        $public_index_content = file_get_contents($public_component_folder."/index.html");

        $public_index_content = str_replace('src="/', 'src="', $public_index_content);

        file_put_contents($public_component_folder."/index.html", $public_index_content);

        try {

            copyContentsFromOneDirectoryToAnother($compiled_folder, $public_component_folder);

        } catch (\Exception $e) {
            return $e->getMessage();
        }

        $app_content = str_replace($component_info['import_statement'], '@/components/HelloWorld.vue', $app_content);
        $app_content = str_replace('import '.$component_file_name, "import HelloWorld", $app_content);
        $app_content = str_replace('<'.$component_file_name.' />', '<HelloWorld />', $app_content);

        file_put_contents($app_path, $app_content);
        file_put_contents($vite_config_path, str_replace($component_info['slug'], 'test1', $vite_config_content));

        return $preview_html;
    }else{
        return "empty";
    }
}


function getChildrenStructureJson($file_path, &$visited = [])
{
    $real_path = realpath($file_path);
    $component_info = getComponentInfo($file_path);
    $project_path = extractProjectPath($file_path);
    if (!$real_path || in_array($real_path, $visited)) {
        return null;
    }

    $visited[] = $real_path;

    $the_code = file_get_contents($real_path);
    $lines = explode("\n", $the_code);

    $root_structure = [
        "path" => $real_path,
        "title" => $component_info["title"],
        "key" => $component_info["slug"],
        "children" => []
    ];

    if (!str_contains($the_code, "@/components")) {
        return $root_structure;
    }

    foreach ($lines as $line) {
        if (str_contains($line, "@/components")) {
            $start_pos = strpos($line, "@");
            $end_pos = strpos($line, ".vue");

            if ($start_pos !== false && $end_pos !== false) {
                $length = $end_pos + 4 - $start_pos;
                $result = substr($line, $start_pos, $length);

                $relative_path = str_replace("@", "", $result);
                $child_component_path = $project_path . 'src/'. $relative_path;
                $child_structure = getChildrenStructureJson($child_component_path, $visited);
                if ($child_structure) {
                    $root_structure["children"][] = $child_structure;
                }
            }
        }
    }

    return $root_structure;
}
